package mlog

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"

	"github.com/astaxie/beego/logs"
)

type Logger struct {
	level     int
	beelogger *logs.BeeLogger
	debug     bool
}

func New(debug bool, strLevel string, pathName string, processID string, settings map[string]interface{}) (*Logger, error) {
	var level int
	switch strings.ToLower(strLevel) {
	case "debug":
		level = logs.LevelDebug
	case "info":
		level = logs.LevelInformational
	case "warn":
		level = logs.LevelWarning
	case "error":
		level = logs.LevelError
	case "fatal":
		level = logs.LevelAlert
	default:
		return nil, errors.New("unknown level: " + strLevel)
	}
	log := logs.NewLogger() // 创建一个日志记录器，参数为缓冲区的大小
	log.SetLogFuncCallDepth(4)
	log.EnableFuncCallDepth(true)
	if debug {
		//控制台
		log.SetLogger(logs.AdapterConsole)
	}
	// 设置配置文件
	if f, ok := settings["file"]; ok {
		ff := f.(map[string]interface{})
		Suffix := ".log"
		if suffix, ok := ff["suffix"]; ok {
			Suffix = suffix.(string)
		}
		ff["filename"] = fmt.Sprintf("%s%s%s", pathName, processID, Suffix)
		config, err := json.Marshal(ff)
		if err != nil {
			logs.Error(err)
		}
		log.SetLogger(logs.AdapterFile, string(config))
	}
	if f, ok := settings["multifile"]; ok {
		multifile := f.(map[string]interface{})
		Suffix := ".log"
		if suffix, ok := multifile["suffix"]; ok {
			Suffix = suffix.(string)
		}
		multifile["filename"] = fmt.Sprintf("%s%s%s", pathName, processID, Suffix)
		config, err := json.Marshal(multifile)
		if err != nil {
			logs.Error(err)
		}
		log.SetLogger(logs.AdapterMultiFile, string(config))
	}
	if slack, ok := settings["slack"]; ok {
		config, err := json.Marshal(slack)
		if err != nil {
			logs.Error(err)
		}
		log.SetLogger(logs.AdapterSlack, string(config))
	}
	if jianliao, ok := settings["jianliao"]; ok {
		config, err := json.Marshal(jianliao)
		if err != nil {
			logs.Error(err)
		}
		log.SetLogger(logs.AdapterJianLiao, string(config))
	}
	if conn, ok := settings["conn"]; ok {
		config, err := json.Marshal(conn)
		if err != nil {
			logs.Error(err)
		}
		log.SetLogger(logs.AdapterConn, string(config))
	}
	if smtp, ok := settings["smtp"]; ok {
		config, err := json.Marshal(smtp)
		if err != nil {
			logs.Error(err)
		}
		log.SetLogger(logs.AdapterMail, string(config))
	}
	if es, ok := settings["es"]; ok {
		config, err := json.Marshal(es)
		if err != nil {
			logs.Error(err)
		}
		log.SetLogger(logs.AdapterEs, string(config))
	}
	// level

	// new
	logger := new(Logger)
	logger.level = level
	logger.beelogger = log
	return logger, nil
}

// It's dangerous to call the method on logging
func (logger *Logger) Close() {
	if logger.beelogger != nil {
		logger.beelogger.Close()
	}
	logger.beelogger = nil
}

func (logger *Logger) doPrintf(level int, format string, a ...interface{}) {
	if level > logger.level {
		return
	}
	if logger.beelogger == nil {
		panic("logger closed")
	}
	switch level {
	case logs.LevelDebug:
		logger.beelogger.Debug(format, a...)
	case logs.LevelInformational:
		logger.beelogger.Info(format, a...)
	case logs.LevelWarning:
		logger.beelogger.Warning(format, a...)
	case logs.LevelError:
		logger.beelogger.Error(format, a...)
	case logs.LevelAlert:
		logger.beelogger.Alert(format, a...)
	}
	if logger.debug {
		fmt.Printf(format, a...)
	}
}

func (logger *Logger) Debugf(format string, a ...interface{}) {
	logger.doPrintf(logs.LevelDebug, format, a...)
}

func (logger *Logger) Infof(format string, a ...interface{}) {
	logger.doPrintf(logs.LevelInformational, format, a...)
}

func (logger *Logger) Warnf(format string, a ...interface{}) {
	logger.doPrintf(logs.LevelWarning, format, a...)
}

func (logger *Logger) Errorf(format string, a ...interface{}) {
	logger.doPrintf(logs.LevelError, format, a...)
}

func (logger *Logger) Fatalf(format string, a ...interface{}) {
	logger.doPrintf(logs.LevelAlert, format, a...)
}

var gLogger, _ = New(true, "debug", "./logs/test", "", map[string]interface{}{
	"file": map[string]interface{}{"filename": "test"},
})

// It's dangerous to call the method on logging
func Export(logger *Logger) {
	if logger != nil {
		gLogger = logger
	}
}

func Debugf(format string, a ...interface{}) {
	gLogger.doPrintf(logs.LevelDebug, format, a...)
}

func Infof(format string, a ...interface{}) {
	gLogger.doPrintf(logs.LevelInformational, format, a...)
}

func Warnf(format string, a ...interface{}) {
	gLogger.doPrintf(logs.LevelWarning, format, a...)
}

func Errorf(format string, a ...interface{}) {
	gLogger.doPrintf(logs.LevelError, format, a...)
}

func Fatalf(format string, a ...interface{}) {
	gLogger.doPrintf(logs.LevelAlert, format, a...)
}

func Close() {
	gLogger.Close()
}
